home *** CD-ROM | disk | FTP | other *** search
/ 130 MIDI Tool Box / 130 MIDI Tool Box.iso / bytemidi / midi.c next >
Text File  |  1986-06-05  |  38KB  |  1,283 lines

  1. /* MIDInterface 1.11
  2.      Copyright (C) 1985, 1986   By:
  3.             Jay Kubicky
  4.             934 N. Orange St.
  5.             Media, PA 19063
  6.             215-565-7761
  7.  
  8.    This is a VERY recent version of this program.
  9.    It has not been 'tested' extensively, though all testing that
  10.    has been done shows favorable results.  
  11.    All users are free, of course, to test (and debug) this software as
  12.    desired.
  13.  
  14.    This program was developed under the DeSmet C compiler, and utilizes
  15.    DeSmet's vastly useful in-line assembly language capability.
  16.    Compiling it on other compilers (such as Lattice) may require 
  17.    EXTENSIVE modification.
  18.  
  19.    2/14/86
  20. */
  21.  
  22. #define MIDID 0xffa0
  23. #define MIDIS 0xffa2
  24. #define PIC0  0x20
  25. #define PIC1  0x21
  26. #define CSTAT 0xFFA7
  27. #define COUNTER1 0xFFA4
  28. #define COUNTER2 0xFFA5
  29. #define Tsize 25600    /* track size in bytes (24K) */
  30. #define Tk 25        /* track size in K */
  31. #define seg_per_trk 1600    /* track size in paragraphs */
  32. /* the following structures hold data for each buffer */
  33.  
  34. char prog_id[]={"MIDInterface 1.11 (c) 1985, 1986  Jay Kubicky"};
  35.  
  36. struct rec      {     /* 63 bytes long    63*16=1008 bytes total */
  37.         char chan;
  38.         unsigned ssize;
  39.         char name[40];
  40.     char transpose;    /* transpose amount */
  41.         char extra[19];  /* for later use */
  42.                 } parts[16];
  43.  
  44. char in_filt;        /* This is the MIDI input filter mask:
  45.                 bit:    message filtered out:
  46.                 ---    --------------------
  47.                  0    Note ON
  48.                  1    Note OFF
  49.                  2    Program Change
  50.                  3    Channel Pres. (After-touch)
  51.                  4    Pitch Wheel
  52.                  5    Control Change
  53.                  6    Poly. Key pres. (After-touch)
  54.             */
  55. char on[4]="ON ";    /* 'ON' */
  56. char off[4]="OFF";    /* 'OFF' */
  57. char yes[4]="YES";
  58. char no[4]="NO ";
  59. char sin_line[80];    /* A 79 char. single line */
  60. unsigned r_segment;
  61. char *ptr, *end;
  62. int fd;  char filename[30];
  63.  
  64. int r_tempo;        /* tempo val (bpm) */
  65. unsigned tempo;        /* real tempo val. */
  66. char destbyte, stop;
  67. char clsb, cmsb, dsync, MIDIsync, audmet;
  68. char rbuff;             /* receive buffer */
  69. char beat, mbeat,abeat, s_t_b, m_t_b, a_t_b; /* beats & time bases */
  70.  
  71. char buffon[16];        /* true means given buff is active */
  72. unsigned pointers[16];  /* an array of pointers into present buffers */
  73. unsigned startp[16];    /* an array of starts of present buffer */
  74. unsigned endp[16];      /* pointers to end of songs */
  75. unsigned segment[16];   /* array of segments of tracks */
  76.  
  77. int pfd;                /* fd for printer */
  78. char printer;           /* printer enable */
  79.  
  80. extern unsigned _rax, _rbx, _rdx, _res, _rds;
  81.  
  82. char LAST_STAT;
  83. char C_O_F;
  84. char clk_type;        /* 0=internal,  1=external */
  85. char counter_dec;
  86. char vir_buff[1024];
  87. char buff1[Tsize];    /* track 0 - 3070 notes */
  88. char buff2[Tsize];    /* track 1 - 3070 notes */
  89.     /* first two tracks eat up  50K */
  90.     /* last fourteen will take 350K combined */
  91.     /* total note storage=
  92.             3200 notes per track
  93.                51200 notes in all!!!     */
  94.  
  95. char *_showsp(),*_showss(),*_showds();
  96. main()
  97. {
  98.     unsigned a;
  99.         char clkval,sel,b;    int c;
  100.         unsigned base_seg, cont_mem;
  101.  
  102.     /* the following code stores the DS at 0x4FA  */
  103.     /*     THIS IS VERY IMPORTANT!!!!!!!!         */
  104.     /* this allows the DS to be transffered to the RXINT function */
  105. # asm
  106.    MOV CX,DS  ; store DS in CX
  107.    PUSH DS    ; save DS
  108.    MOV AX,0   ; this will be new value for DS
  109.    MOV DS,AX  ; put 0 in DS
  110.    MOV WORD [04FAH], CX   ; store DS
  111.    POP DS     ; retrieve DS
  112. #
  113.  
  114.         /*       MIDInterface 1.11 16-track digital sequencer
  115.  
  116.                          Data storage format:
  117.                          --------------------
  118.  
  119.                         (MIDI ORIENTED COMMANDS)
  120.    byte num:     first      second     third      fourth     fifth
  121.                 +--------+----------+----------+----------+--------+
  122.    Note ON      00vvvvvv | LLLLLLLL | MMMMMMMM | 1nnnnnnn |   --
  123.                          |          |          |          |
  124.    Note OFF     00vvvvvv | LLLLLLLL | MMMMMMMM | 0nnnnnnn |   --
  125.                          |          |          |          |
  126.    Prog Chan    01000000 | LLLLLLLL | MMMMMMMM | 0ppppppp |   --
  127.                          |          |          |          |
  128.    Chan Pres    01000001 | LLLLLLLL | MMMMMMMM | 0aaaaaaa |   --
  129.    (after-touch)         |          |          |          |
  130.    Pitch Wheel  10wwwwww | LLLLLLLL | MMMMMMMM |    --    |   --
  131.                          |          |          |          |
  132.    Cntrl Chan   11000000 | LLLLLLLL | MMMMMMMM | 0nnnnnnn | 0ccccccc
  133.              |        |           |      |
  134.    Key Pres.    011vvvvv | LLLLLLLL | MMMMMMMM | 0nnnnnnn |   --
  135.    (after-touch)
  136.  
  137.                         (INTERNAL ORIENTED COMMANDS)
  138.                 +--------+----------+----------+----------+--------+
  139.    Change Tempo 11000001 | LLLLLLLL | MMMMMMMM | tttttttt |   --
  140.  
  141.    End          11111111 |    --    |    --    |    --    |   --
  142.  
  143.  
  144. -------------------------------------------------------------------------
  145.         vvvvvv  - top 6 bits of velocity (NOTE ON or OFF)
  146.       LLLLLLLL  - LSB of clk
  147.       MMMMMMMM  - MSB of clk
  148.        nnnnnnn  - note for either NOTE ON or NOTE OFF
  149.        ppppppp  - new program
  150.        aaaaaaa  - chan pressure (after-touch)
  151.         wwwwww  - top six of bender
  152.        nnnnnnn  - control number
  153.        ccccccc  - control value
  154.  
  155.       tttttttt  - new tempo value (40-200)
  156. */
  157.     c=0;
  158.     while(c<79)
  159.         sin_line[c++]='─';
  160.     sin_line[c]='\0';
  161.  
  162.     in_filt=0xff;    /* Don't filter out anything */
  163.     clk_type=0;    /* internal */
  164.     counter_dec=2;
  165.         rbuff=255;
  166.     segment[0]=segment[1]=_showds();    /* 1st two buffs in DS */
  167.     startp[0]=buff1;    endp[0]=buff1+Tsize-8;
  168.     startp[1]=buff2;    endp[1]=buff2+Tsize-8;
  169.     parts[0].ssize=0;    parts[1].ssize=0;
  170.  
  171.     /* This is the memory allocation section.
  172.        This is really a sort of pseudo-allocation scheme
  173.        allowing the use of the entire system memory (up to 640K).
  174.        Memory is allocated in blocks of 25k (1600 paragraphs).
  175.        All tracks are allocated sequentially until you run out
  176.        of system RAM.  The first two tracks are taken care of
  177.        in the C memory, so there should always be room for these.
  178.     */
  179.  
  180.         base_seg=_showss()+1;    /* start just after stack */
  181.     base_seg += (_showsp()/16);    /* This is the segment boundary of
  182.                        the bottom of un-initialized mem */
  183.     ++base_seg;    /* one for a safety */
  184.  
  185.     cont_mem=get_av_mem();
  186.     cont_mem *= 64;    /* Find total # of system para. */
  187.  
  188.     /* Here's where we "allocate our memory" */
  189.  
  190.     _setmem(segment+4,28,0);
  191.         c=2;
  192.         for (a=base_seg; a < cont_mem && c < 16; a+=seg_per_trk)     {
  193.         segment[c]=a;
  194.         startp[c]=0;
  195.         endp[c]=Tsize-8;
  196.         parts[c].ssize=0;
  197.         parts[c].transpose=0;
  198.         ++c;
  199.         }
  200.         m_t_b=2;  s_t_b=1;  a_t_b=48;   /* default time bases */
  201.         printer=0;
  202.         scr_cla();
  203.         printf("Do you wish to use the printer as an audio meternome?");
  204.         if(toupper(getchar())=='Y')     {
  205.                 printf("\nReady the printer and hit any key");
  206.                 getchar();
  207.                 if((pfd=open("PRN",2))==-1)     {
  208.                         printf("Error opening printer ... aborting\n");
  209.                         getchar();
  210.                         exit(1);
  211.                                                 }
  212.                 beepp();
  213.                 printer=1;
  214.                                         }
  215. start:
  216.         setdart();
  217.         intoff();   /* turn interrupts off */
  218.         scr_cla();
  219. printf("             ╔════════════════════════════════════════════════╗\n");
  220. printf("             ║  MIDInterface 1.11  16 Track Digital Recorder  ║\n");
  221. printf("             ╚════════════════════════════════════════════════╝\n");
  222. printf("\n");
  223. printf("                               Main Menu:\n");
  224. printf("                               ──────────\n");
  225. printf("                       1..........Erase a track\n");
  226. printf("                       2..........Record to a track\n");
  227. printf("                       3..........Play from a track\n");
  228. printf("                       4..........Track information\n");
  229. printf("                       5..........Save a track\n");
  230. printf("                       6..........Load a track\n");
  231. printf("                       7..........Set MIDI modes\n");
  232. printf("                       8..........Edit input filter\n");
  233. printf("                       0..........Quit\n");
  234.     scr_rowcol(24,0);
  235. printf("                  Copyright (C) 1985, 1986 by Jay Kubicky");
  236.     scr_rowcol(18,0);
  237. printf("                             Enter Selection:");
  238.         sel=getchar();
  239.         switch (sel)    {
  240.                 case '1':
  241.                         erbuff();
  242.                         break;
  243.                 case '2':
  244.                         recbuff();
  245.                         break;
  246.                 case '3':
  247.                         pbuffs();
  248.                         break;
  249.                 case '4':
  250.                         dbuffs();
  251.                         break;
  252.                 case '5':
  253.                         strack();
  254.                         break;
  255.                 case '6':
  256.                         ltrack();
  257.                        break;
  258.                 case '7':
  259.                         mmode();
  260.                         break;
  261.         case '8':
  262.             ed_in_filt();
  263.             break;
  264.                 case '0':
  265.                         scr_cla();
  266.                         b=0;
  267.                         for(a=0; a<16; ++a)     {
  268.                                 if(parts[a].ssize)      {
  269.                                         b=1; /* toggle high */
  270.                                         printf("   Data still left in track %d\n",a);
  271.                                                         }
  272.                                                 }
  273.                         if(!b)                          {
  274.                                 close(pfd);
  275.                                 exit(0);
  276.                                                         }
  277.                         printf("Still want to exit? ");
  278.                         if(toupper(getchar()) == 'Y')   {
  279.                                 close(pfd);
  280.                                 exit(0);
  281.                                                         }
  282.                 default:
  283.                         goto start;
  284.                         }
  285.         goto start;
  286. }
  287.  
  288. /*    DBUFFS
  289.     This is the general buffer display routine.
  290.     It displays all pertinent data for all avaiable buffers.
  291. */
  292. dbuffs()
  293. {
  294.         char a,b; unsigned tn,nf,nu;
  295. s_:     scr_cla();
  296.         printf("                   Track Assignment Screen:\n");
  297.         printf("                   ════════════════════════\n");
  298.         printf("Track Num:   Transmit Chan:    Notes Used:   Transpose:      Enabeled:\n");
  299.         printf("%s\n",sin_line);
  300.         for(a=0; a<16; ++a)   {
  301.         if(segment[a])    {
  302.                     tn=(endp[a]-startp[a])/8;
  303.                     nf=tn-(parts[a].ssize/8);
  304.                     nu=tn-nf;
  305.             b=parts[a].transpose;
  306.                     printf("%d\t\t%d\t\t%d\t\t%d\t\t%s\n",a,parts[a].chan,nu,b < 128 ? b : -256+b, buffon[a] || (a==rbuff) ? yes : no);
  307.         }
  308.         else
  309.             printf("--\t\t--\t\t--\t\t--\t\t--\n");
  310.         }
  311.         printf("%s\n",sin_line);
  312. ttag:    scr_rowcol(21,0);
  313.         printf("Chng one trans. channel (1), change all (2), transpose (3), enable status (4)\n");
  314.     printf("or (0) to quit/continue: ");
  315.         a=getchar();
  316.         scr_rowcol(22,17);
  317.         scr_cls();  /* clear rest of current line */
  318.         switch(a)    {
  319.         case '0':
  320.                     return;
  321.             break;
  322.         case '1':
  323.                     printf("   Enter track number:");
  324.                     b=getint();
  325.                     scr_rowcol(23,0);
  326.                     printf("   Enter new transmit channel:");
  327.                     parts[b].chan=getint();
  328.                 break;
  329.         case '2':
  330.                     printf("   Enter new transmit channel for all tracks:");
  331.                     a=getint();
  332.                     for(b=0; b<16; ++b)
  333.                             parts[b].chan=a;
  334.             break;
  335.         case '3':
  336.             printf("   Enter track number:");
  337.                     b=getint();
  338.                     scr_rowcol(23,0);
  339.                     printf("   Enter new transpose amount:");
  340.                     parts[b].transpose=getint();
  341.                 break;
  342.         case '4':
  343.             printf("   Enter track number:");
  344.             b=getint();
  345.             if(parts[b].ssize && b != rbuff)
  346.                 buffon[b]= buffon[b] ? 0 : 1;
  347.             break;
  348.         default:
  349.             goto ttag;
  350.     }
  351.         goto s_;
  352. }
  353.  
  354. /*    ERBUFF
  355.     This funct. erase a buffer (set the size to 0)
  356. */
  357. erbuff()
  358. {
  359.         scr_cla();
  360.         char b;
  361.     printf("                          Erase a Track\n");
  362.     printf("%s\n",sin_line);
  363.         printf("\nWhich buffer? ");
  364.         b=getint();
  365.         printf("Are you sure you want to erase buffer %d?",b);
  366.         if(toupper(getchar()) != 'Y')
  367.                 return;
  368.         parts[b].ssize=0;
  369.         buffon[b]=0;
  370. }
  371.  
  372. /*    PBUFFS
  373.     This is the top-level play-buffer routine.
  374. */
  375. pbuffs()
  376. {
  377.         int m;
  378.         copyptrs();
  379.  
  380.         scr_cla();
  381.     printf("                           Play Track Mode\n");
  382.         printf("%s\n\n\n",sin_line);
  383.     printf("   Hit any key to continue\n");
  384.         getchar();
  385.         dbuffs();
  386.  
  387.         scr_cla();
  388.     printf("                           Play Track Mode\n");
  389.         printf("%s\n\n\n",sin_line);
  390.  
  391.     get_options();
  392.  
  393.         printf("\nHit space bar to continue, any other key to quit\n");
  394.         if(getchar()!=32)
  395.                 return;
  396.         setrec();
  397.         destbyte=0xff;
  398.         play();
  399.         intoff();
  400.         _outb(5,MIDIS);    /* send off to drum mach. */
  401.         _outb(104,MIDIS);
  402.         _outb(0xfc,MIDID);  /* MIDI seq off */
  403.         for(m=0; m<16; ++m)     {
  404.                 if(parts[m].ssize)
  405.                         buffon[m]=1;
  406.                                 }
  407. }
  408.  
  409. /*
  410.     RECBUFF:
  411.     This is the track record routine.
  412.     All it really does is set up & enable the interrupt routine -
  413.     RxInt
  414. */
  415. recbuff()
  416. {
  417.         char b;  int m;
  418.         copyptrs();
  419.         scr_cla();
  420.     printf("                        Record a Track\n");
  421.         printf("%s\n\n",sin_line);
  422.     printf("        Which buffer:");
  423.         b=getint();
  424.         if(parts[b].ssize)      {
  425.                 printf("That buffer already has music, still want to record (Y/N)?");
  426.                 if(toupper(getchar()) != 'Y')
  427.                         return;
  428.                                 }
  429.     if(!segment[b])    {
  430.         printf("Sorry, that track is not available to record in.\n");
  431.         hak();
  432.         return;
  433.     }
  434.         rbuff=b;
  435.     parts[b].ssize=0;
  436.         dbuffs();  /* display buff enable board w/ option to change */
  437.         scr_cla();
  438.  
  439.     get_options();
  440.  
  441.         printf("\nHit any key to begin recording\n");
  442.         getchar();
  443.         scr_cla();
  444.         printf("Hit any key to stop recording\n");
  445.  
  446.         setrec();
  447.         play();
  448.  
  449.         _poke(255,ptr,segment[rbuff]);    /* EOS (end-of-song) */
  450.         parts[b].ssize=ptr-startp[rbuff];
  451.         printf("\nSong is %d notes long\n",parts[b].ssize / 8);
  452.         rbuff=255;              /* no more record buffer */
  453.         pointers[b]=startp[b];  /* copy start pointer */
  454.         buffon[b]=1;            /* enable present buffer */
  455.  
  456.         _outb(5,MIDIS);    /* send off to drum mach. */
  457.         _outb(104,MIDIS);
  458.         _outb(0xfc,MIDID);  /* MIDI seq off */
  459.  
  460.     rbuff=0xff;
  461.     hak();
  462. }
  463.  
  464. /*    SETREC
  465.     This sets up almost everything for Play & Record.
  466. */
  467. setrec()
  468. {
  469.     int a;
  470.  
  471.         stop=0;
  472.         destbyte=0;
  473.         setint();
  474.         ptr=startp[rbuff];
  475.     end=endp[rbuff];
  476.     r_segment=segment[rbuff];
  477.         end=endp[rbuff];
  478.         C_O_F=0x90;
  479.         beat=abeat=mbeat=0xfe;
  480.         if(dsync)      {
  481.                 _outb(5,MIDIS);  /* send start to drums */
  482.                 _outb(104+128,MIDIS);
  483.         }
  484.         if(MIDIsync)
  485.                 _outb(0xfa,MIDID);      /* start ext seq */
  486.     pointers[0]=startp[0];
  487.     pointers[1]=startp[1];
  488.         setcounter(tempo & 0xff,tempo >> 8,255,255);
  489. }
  490.  
  491. copyptrs()  /* copy start pstns of buffers into pointer areas  */
  492. {
  493.         char a;
  494.         for(a=0; a<15; ++a)
  495.                 pointers[a]=startp[a];
  496. }
  497.  
  498. /*    LTRACK
  499.     Load a track into memory.
  500. */
  501. ltrack()
  502. {
  503.         char tr;
  504.         scr_cla();
  505.     printf("                        Load a Track\n");
  506.         printf("%s\n",sin_line);
  507.     dir("????????","???");
  508.     scr_rowcol(2,0);
  509.     printf("   Load which track:");
  510.         tr=getint();
  511.         if(parts[tr].ssize)             {
  512.                 printf("Data already in that track ... aborting.\n");
  513.                 getchar();  return;     }
  514.         printf("  Load from which file:");
  515.         scanf("%s",filename);
  516.         if((fd=open(filename,2)) == -1)  {
  517.                 printf("Can't open %s ... aborting\n",filename);
  518.                 getchar();
  519.                 return;
  520.                                         }
  521.         if(read(fd,parts[tr],63) == -1)        {
  522.                 printf("Error encountered during reading.\n");
  523.                 getchar();
  524.                 return;
  525.                                                 }
  526.         if(seg_read(fd,tr,parts[tr].ssize+1) == -1)  {
  527.                 printf("Error encountered while reading.\n");
  528.                 getchar();  return;                     }
  529.         close(fd);
  530.         printf("Total bytes loaded from disk:%d\n",parts[tr].ssize+63);
  531.         buffon[tr]=1;
  532.         getchar();
  533. }
  534.  
  535. /*    STRACK
  536.     Save a track to disk.
  537. */
  538. strack()  /* save a track */
  539. {
  540.         char tr;
  541.         scr_cla();
  542.     printf("                        Save a Track\n");
  543.         printf("%s\n",sin_line);
  544.     dir("????????","???");
  545.     scr_rowcol(2,0);
  546.     printf("   Save which track:");
  547.     tr=getint();
  548.         if(!parts[tr].ssize)             {
  549.                 printf("Nothing in that track ... aborting.\n");
  550.                 getchar();  return;     }
  551.         printf("  Save to what file:");
  552.         scanf("%s",filename);
  553.         if((fd=creat(filename)) == -1)  {
  554.                 printf("Can't creat %s ... aborting\n",filename);
  555.                 getchar();
  556.                 return;
  557.                                         }
  558.         if(write(fd,parts[tr],63) == -1)        {
  559.                 printf("Error encountered during writing.\n");
  560.                 getchar();
  561.                 goto _end;
  562.                                                 }
  563.         if(seg_write(fd,tr,parts[tr].ssize+1) == -1)  {
  564.                 printf("Error encountered while writing.\n");
  565.                 getchar();   goto _end;                 }
  566.         close(fd);
  567.         printf("Total bytes written to disk:%d\n",parts[tr].ssize+63);
  568.         hak();     
  569.         return;
  570. _end:
  571.         close(fd);
  572. }
  573.  
  574. /*    SEG_READ, SEG_WRITE
  575.     These functions carry out intra-segmentary disk I/O functions.
  576. */
  577. seg_read(fd,tr,size)
  578. int fd, tr;  unsigned size;
  579. {
  580.         unsigned a;
  581.     a=startp[tr];    /* this won't be 0 for tr. 0 & 1 : it's a pointer */
  582.  
  583.         if(size > 1024) {
  584.         size+=a;    /* make size look like a pointer */
  585.                 for(;a < (size-1024); a+=1024)      {
  586.                         if(read(fd,vir_buff,1024) == -1)
  587.                                 return(-1);
  588.                         _lmove(1024,vir_buff,_showds(),a,segment[tr]);
  589.                 }
  590.         }
  591.         else
  592.                 size+=a;
  593.  
  594.         if(!(size-a))
  595.                 return(1);
  596.         if(read(fd,vir_buff,size-a) == -1)
  597.                 return(-1);
  598.         _lmove(size-a,vir_buff,_showds(),a,segment[tr]);
  599.         return(1);
  600. }
  601.  
  602. seg_write(fd,tr,size)
  603. int fd, tr;  unsigned size;
  604. {
  605.     unsigned a;
  606.     a=startp[tr];    /* this won't always be 0 because of tracks 0 & 1 */
  607.  
  608.     if(size > 1024) {
  609.         size+=a;    /* make size look like a pointer */
  610.         for(;a < (size-1024); a+=1024)      {
  611.             _lmove(1024,a,segment[tr],vir_buff,_showds());
  612.             if(write(fd,vir_buff,1024) == -1)
  613.                 return(-1);
  614.         }
  615.     }
  616.     else
  617.                 size+=a;
  618.  
  619.         if(!(size-a))    /* Is the buff length 0 || have we written all data? */
  620.                 return(1);
  621.         _lmove(size-a,a,segment[tr],vir_buff,_showds());
  622.         if(write(fd,vir_buff,size-a) == -1)
  623.                 return(-1);
  624.         return(1);
  625. }
  626.  
  627. /* play() -
  628.     This function plays through the 16 tracks until track 0 ends
  629.     or a key is struck.
  630. */
  631. play()
  632. {
  633.     int playing;
  634.         char a,ch,b;
  635.     unsigned n;
  636.     scr_rowcol(2,0);
  637.     printf("Tempo:    %d",r_tempo);
  638. sp:
  639.         for (a=0; a<15; ++a)    {
  640.                 if(buffon[a] && a!=rbuff)       {
  641.             if(playfrom(a))    {    /* Track or song end */
  642.                 if(a)        /* if not track 0 */
  643.                     buffon[a]=0;    /* turn off buff */
  644.                 else
  645.                     return;
  646.             }
  647.         }
  648.         if(dsync)
  649.             bt();
  650.         if(MIDIsync)
  651.             bt2();
  652.         if(audmet)
  653.             bt3();
  654.     }
  655.         if(!(ch=scr_csts()))
  656.         goto sp;
  657.     else {
  658.         switch(ch)    {
  659.             case '+':
  660.                 ++r_tempo;
  661.                 break;
  662.             case '-':
  663.                 --r_tempo;
  664.                 break;
  665.             default:
  666.                 return;
  667.         }
  668.         scr_rowcol(2,10);
  669.         printf("%d",r_tempo);
  670.         tempo=2000000/((r_tempo*48)/60);
  671.         set_cnt_1(tempo,tempo >> 8);
  672.     }
  673.     goto sp;
  674. }
  675. playfrom(a)
  676. char a;
  677. {
  678.         char *p,d,*p1;
  679.         p=vir_buff;
  680.         _lmove(8,pointers[a],segment[a],vir_buff,_showds());
  681.  
  682.         if(*p==0xff)     /* check for EOS */
  683.         return(1);
  684.  
  685.         readclk();
  686.     p1=p+2;
  687.         if(*p1 > cmsb)
  688.                 goto pnow;
  689.         if(*p1 <  cmsb)
  690.                 return(0);
  691.         if(*(p+1) <  clsb)
  692.                 return(0);
  693. pnow:   /* now we know that it's time to play [notes]... */
  694.         d=*p & 0xc0;
  695.         switch(d)       {
  696.                 case 00:        /* note on or off */
  697.                         pnt(p,parts[a].chan,parts[a].transpose);
  698.                         pointers[a]+=4;
  699.                         break;
  700.                 case 0x40:      /* prog chan / chan pres. / key pres. */
  701.                         pchan(p,parts[a].chan);
  702.                         pointers[a]+=4;
  703.                         break;
  704.                 case 0x80:      /* pitch bender */
  705.                         w_f_e();        /* let FIFO empty */
  706.                         _outb(0xE0+parts[a].chan,MIDID); /* send P. B. code */
  707.                         w_f_e();        /* let FIFO empty */
  708.                         _outb(0,MIDID);  /* we didn't store LSB */
  709.                         w_f_e();
  710.                         _outb(*p << 1,MIDID); /* send MSB */
  711.                         pointers[a]+=3;
  712.                         break;
  713.                 case 0xC0:      /* cntrl chan | temp chan */
  714.             cchan(p,parts[a].chan);
  715.             if(!(*p&1)); /* make up for control change */
  716.                 ++pointers[a];
  717.             pointers[a]+=4;
  718.             break;
  719.     }
  720.         return(0);
  721. }
  722.  
  723. pnt(p,tc,trans)
  724. char *p,tc,trans;
  725. {
  726. # asm
  727.         MOV SI,WORD [BP+4]      ; get p
  728.         MOV AL,BYTE [SI+3]      ; get *(p+3)
  729.         AND AL,128              ; strip off top bit
  730.         JZ znoff                ; play a note off
  731.         MOV AL,BYTE [BP+6]      ; get tchan
  732.         ADD AL,090H             ; add a basic note on
  733. zcheat1:                        ; here's where we'll cheat on a Note OFF
  734.         MOV DX,0FFA0H           ; MIDI Data port
  735.         CALL w_f_e_             ; wait for DART FIFO to empty
  736.         OUT DX,AL               ; send byte
  737.         MOV AL,BYTE [SI+3]      ; get note to turn on
  738.     ADD AL,BYTE [BP+8]    ; add transpose val.
  739.         AND AL,07FH             ; strip off top bit
  740.         CALL w_f_e_             ; wait for DART FIFO to empty
  741.         OUT DX,AL               ; send out note
  742.         MOV AL,BYTE [SI]        ; get velocity
  743.         SHL AL,1                ; shift up into range
  744.         CALL w_f_e_             ; wait for DART FIFO to empty out
  745.         OUT DX,AL               ; send velocity
  746.         JMP zalldone            ; finished
  747.  
  748. znoff:                          ; send Note OFF command
  749.         MOV AL,BYTE [BP+6]      ; get transmit channel
  750.         ADD AL,080H             ; add basic Note OFF
  751.         JMP zcheat1             ; let's take a short cut
  752.  
  753. zalldone:                       ; all done
  754.  
  755. #
  756. }
  757.  
  758. pchan(p,tc)    /* Program change, channel pressure, or after-touch */
  759. char *p,tc;
  760. {
  761. # asm
  762.     MOV DX,0FFA0H        ; DART port
  763.         MOV SI,WORD [BP+4]      ; get p
  764.         MOV AL,BYTE [SI]        ; get I.D. byte
  765.         CMP AL,040H             ; I.D. for Prog change
  766.         JZ zpchan               ; branch if Prog change
  767.     CMP AL,041H        ; I.D. for Chan pressure, after-touch
  768.     JZ zchanp
  769.                 ; else, Poly. key press. (after-touch)
  770.     MOV AL,BYTE [BP+6]      ; get transmit chan
  771.         ADD AL,0A0H        ; poly. key pressure
  772.     CALL w_f_e_
  773.     OUT DX,AL        ; send 1st byte
  774.     MOV AL,BYTE [SI+3]    ; get key #
  775.     CALL w_f_e_
  776.     OUT DX,AL
  777.     MOV AL,BYTE [SI]    ; get pressure
  778.     AND AL,01FH        ; strip off bottom 5
  779.     SHL AL,1
  780.     SHL AL,1        ; bumb up two bits
  781.     CALL w_f_e_
  782.     OUT DX,AL
  783.     JMP zalldone2        ; all done
  784.  
  785. zpchan:                         ; program change
  786.         MOV AL,BYTE [BP+6]      ; get transmit channel
  787.         ADD AL,0C0H             ; basic prog chan
  788.         JMP zcheat2             ; use code from above routine
  789. zchanp:                ; channel pressure
  790.     MOV AL,BYTE [BP+6]    ; get transmit channel
  791.     ADD AL,0D0H        ; add basic chan pres
  792.     JMP zcheat2
  793. zcheat2:                        ; entry point from zpchan
  794.         CALL w_f_e_             ; wait for DART
  795.         OUT DX,AL               ; send byte
  796.         MOV AL,BYTE [SI+3]      ; get new vel
  797.         OUT DX,AL               ; send
  798.  
  799. zalldone2:                      ; FINE
  800. #
  801. }
  802.  
  803. cchan(p,tc)
  804. char *p,tc;
  805. {
  806. # asm
  807.         MOV SI,WORD [BP+4]      ; get p
  808.         MOV AL,BYTE [SI]        ; get I.D. byte
  809.         AND AL,1                ; bit 0
  810.         JNZ ztchan              ; tempo change
  811.                                 ; now we know it's a cntrl chan
  812.         MOV AL,0B0H             ; cntrl chan
  813.         ADD AL,BYTE [BP+6]      ; add transmit channel
  814.         MOV DX,0FFA0H           ; MIDID port
  815.         CALL w_f_e_             ; wait for DART to empty
  816.         OUT DX,AL
  817.         MOV AL,BYTE [SI+3]      ; get cntrl #
  818.         CALL w_f_e_             ; wait for DART FIFO to empty
  819.         OUT DX,AL
  820.         MOV AL,BYTE [SI+4]      ; get cntrl val
  821.         CALL w_f_e_
  822.         OUT DX,AL
  823.         JMP _fine2              ; done
  824.  
  825. ztchan:                         ; tempo change
  826.     ;   MOV AL,extsync_
  827.     ;   OR AL,AL                ; set flags
  828.     ;   JNZ _fine2              ; if extsync mode, then this has no purpose
  829. #
  830.     /*  tempo(*(p+3)+30);   */
  831. # asm
  832.  
  833. _fine2:
  834.  
  835. #
  836. }
  837.  
  838. w_f_e()  /* this function "sleeps" until the FIFO in the DART is empty */
  839. {
  840. # asm
  841.         PUSH DX
  842.         PUSH AX
  843.         MOV DX,0FFA2H           ; DART status register
  844. try_again:
  845.         IN AL,DX
  846.         AND AL,4                ; Tx buff empty?
  847.         JZ try_again            ; no?
  848.         POP AX
  849.         POP DX
  850. #
  851. }
  852. /*
  853.     BT, BT2, BT3
  854.     These are the meternome counting routines.
  855. */
  856. bt()
  857. {
  858.         readclk();
  859.         if(beat==clsb)  {
  860.                 _outb(5,MIDIS+1);  /* send sync high */
  861.                 _outb(128,MIDIS+1);
  862.                 _outb(5,MIDIS+1);  /* send sync low */
  863.                 _outb(0,MIDIS+1);
  864.                 beat-=s_t_b;
  865.         }
  866. }
  867.  
  868. bt2()
  869. {
  870.         readclk();
  871.         if(mbeat==clsb) {
  872.                 _outb(0xf8,MIDID);  /* MIDI timing clk */
  873.                 mbeat-=m_t_b;
  874.                         }
  875. }
  876.  
  877. bt3()
  878. {
  879.         readclk();
  880.         if(abeat==clsb) {
  881.                 if(printer)
  882.                         beepp();
  883.                 abeat-=a_t_b;
  884.                         }
  885. }
  886. beepp()
  887. {
  888.         _rax=0x0500;
  889.         _rdx=7;
  890.         _doint(0x21);
  891. }
  892. /*    SETINT
  893.     This routine sets up the interrupt.
  894. */
  895. setint()
  896. {
  897.  
  898.  
  899.         int rxint(),a;
  900.         int seg_num, (*fun_add)();
  901.  
  902.         fun_add = rxint;
  903.         seg_num=_showcs();
  904.         _poke(fun_add & 0xff,0x28,0);  _poke(fun_add >> 8,0x29,0);
  905.         _poke(seg_num & 0xff,0x2a,0);  _poke(seg_num >> 8,0x2b,0);
  906.         setdart();
  907.         setpic();
  908. }
  909.  
  910. setdart()
  911. {
  912.         _outb(24,MIDIS);   /* reset channel A */
  913.         _outb(1,MIDIS);    _outb(24,MIDIS);  /* int on all Rx + Ext Stat */
  914.         _outb(3,MIDIS);    _outb(193,MIDIS);
  915.         _outb(4,MIDIS);    _outb(196,MIDIS);
  916.         _outb(5,MIDIS);    _outb(104,MIDIS);
  917. }
  918. setpic()
  919. {
  920.         char a;
  921.         a=_inb(PIC1);  /* read interrupt mask */
  922.         if(a&4)         /* if DART is masked off */
  923.                 a-=4;
  924.         _outb(a,PIC1);   /* re-enable ints */
  925. }
  926.  
  927. setcounter(l1,m1,l2,m2)
  928. char l1,m1,l2,m2;
  929. {
  930.         char e,d;
  931.         _outb(0x34,CSTAT);   /* counter 1=mode 2 - read/load both  */
  932.         e=d; d=e;
  933.         _outb(0x70,CSTAT);  /* counter 2= mode 0 - read/load both */
  934.         e=d; d=e;
  935.         _outb(l2,COUNTER2);  /* set LSB of counter 2 */
  936.         e=d; d=e;
  937.         _outb(m2,COUNTER2);  /* set MSB of counter 2 */
  938.         e=d; d=e;
  939.         _outb(l1,COUNTER1);    /* set LSB of counter 1 */
  940.         e=d; d=e;
  941.         _outb(m1,COUNTER1);  /* set MSB of counter 1 */
  942.         readclk();
  943.         while(cmsb!=255 && clsb!=255)
  944.                 readclk();
  945.         return;
  946. }
  947. set_cnt_1(l1,m1)
  948. char l1,m1;
  949. {
  950.         _outb(l1,COUNTER1);  /* set LSB of counter 1 */
  951.         _outb(m1,COUNTER1);  /* set MSB of counter 1 */
  952. }
  953.  
  954. intoff()
  955. {
  956.         _outb(01,MIDIS);    /* turn off my interrupt */
  957.         _outb(00,MIDIS);    /* (at the DART) */
  958. }
  959. inton()
  960. {
  961.         _outb(01,MIDIS);    /* turn on my interrupt */
  962.         _outb(24,MIDIS);    /* (at the DART) */
  963. }
  964. readclk()
  965. {
  966. # asm
  967.         MOV AL,64
  968.         MOV DX,0FFA7H
  969.         CLI            ; an interrupt right now from Rxint would be bad
  970.         OUT DX,AL
  971.         NOP
  972.         NOP
  973.         NOP
  974.         SUB DX,2
  975.         IN AL,DX
  976.         MOV clsb_,AL
  977.         NOP
  978.         NOP
  979.         NOP
  980.         IN AL,DX
  981.         MOV cmsb_,AL
  982.         STI             ; ints back on
  983. #
  984. }
  985.  
  986. scr_cla()  /* clear screen & pstn cursor at top */
  987. {
  988.         scr_clr();
  989.         scr_rowcol(0,0);
  990. }
  991.  
  992. /*    MMODE
  993.     This is a no-frills routine for setting up various
  994.     MIDI system modes
  995. */
  996. mmode()
  997. {
  998.         char a,mo,v;
  999. st:
  1000.         scr_cla();
  1001.     printf("                        MIDI mode assignments:\n");
  1002.         printf("%s\n",sin_line);
  1003. ss:
  1004.         putchar('\n');
  1005.         printf("        1 - Omni ON  / Poly\n");
  1006.         printf("        2 - Omni OFF / Poly\n");
  1007.         printf("        3 - Omni ON  / Mono\n");
  1008.         printf("        4 - Omni OFF / Mono\n");
  1009.         printf("        5 - Program change\n");
  1010.         printf("        6 - All notes off (all channels)\n");
  1011.         printf("        7 - All notes off (one channel)\n");
  1012.         printf("        0 - Exit\n");
  1013.         printf("Enter new mode:");
  1014.         mo=getint();
  1015.         if(!mo)
  1016.                 return;
  1017.         if(mo>7)
  1018.                 goto st;
  1019.         if(mo==6)
  1020.                 goto skip;
  1021.         printf("Send over which channel:");
  1022.         a=getint();        if(a > 15)
  1023.                 goto ss;
  1024.         printf("\nChannel %d:\n",a);
  1025. skip:
  1026.         switch(mo)      {
  1027.                 case 1:
  1028.                         printf("  Poly / Omni on\n");
  1029.                         poly(a);
  1030.                         o_on(a);
  1031.                         break;
  1032.                 case 2:
  1033.                         printf("  Poly / Omni off\n");
  1034.                         poly(a);
  1035.                         omni_off(a);
  1036.                         break;
  1037.                 case 3:
  1038.                         printf("  Mono / Omni on\n");
  1039.                         mono(a);
  1040.                         o_on(a);
  1041.                         break;
  1042.                 case 4:
  1043.                         printf("  Mono / Omni off\n");
  1044.                         mono(a);
  1045.                         omni_off(a);
  1046.                         break;
  1047.                 case 5:
  1048.                         printf("  Program change\n");
  1049.                         printf("   Enter new program: ");
  1050.                         v=getint();
  1051.                         _outb(192+a,MIDID);
  1052.                         _outb(v,MIDID);
  1053.                         break;
  1054.                 case 6:
  1055.                         for(a=0; a<16; ++a)    {
  1056.                                 _outb(0xb0+a,MIDID);
  1057.                                 _outb(123,MIDID);
  1058.                                 w_f_e();
  1059.                                 _outb(0,MIDID);
  1060.                                                 }
  1061.                         printf(" All notes off - all channels\n");
  1062.                         getchar();
  1063.                         break;
  1064.                 case 7:
  1065.                         _outb(0xb0+a,MIDID);
  1066.                         _outb(123,MIDID);
  1067.                         w_f_e();
  1068.                         _outb(0,MIDID);
  1069.                         printf(" All notes off\n");
  1070.                         getchar();
  1071.                         break;
  1072.                         }
  1073.         goto st;
  1074. }
  1075.  
  1076. o_on(ch)
  1077. char ch;
  1078. {
  1079.         _outb(176+ch,MIDID);
  1080.         _outb(125,MIDID);
  1081.         w_f_e();
  1082.         _outb(0,MIDID);
  1083.         getchar();
  1084. }
  1085.  
  1086. omni_off(ch)
  1087. char ch;
  1088. {
  1089.         _outb(176+ch,MIDID);
  1090.         _outb(124,MIDID);
  1091.         w_f_e();
  1092.         _outb(0,MIDID);
  1093.         getchar();
  1094. }
  1095.  
  1096. poly(ch)
  1097. char ch;
  1098. {
  1099.         _outb(176+ch,MIDID);
  1100.         _outb(127,MIDID);
  1101.         w_f_e();
  1102.         _outb(0,MIDID);
  1103.         getchar();
  1104. }
  1105.  
  1106. mono(ch)
  1107. char ch;
  1108. {
  1109.         char v;
  1110.         printf("How many channels? (0 = # in receiver, or other) ");
  1111.         v=getint();
  1112.         _outb(176+ch,MIDID);
  1113.         _outb(126,MIDID);
  1114.         w_f_e();
  1115.         _outb(v,MIDID);
  1116.         getchar();
  1117. }
  1118.  
  1119. get_av_mem()  /* returns total system RAM - in K */
  1120. {
  1121.         _doint(0x012);
  1122.         return(_rax);
  1123. }
  1124.  
  1125. char *_showss()
  1126. {
  1127. # asm
  1128.     MOV AX,SS
  1129. #
  1130. }
  1131.  
  1132. hak()    /* display "hit any key to continue" & wait */
  1133. {
  1134.     puts("\n\n");
  1135.     scr_cls();
  1136.     puts("                            Hit any key to continue.");
  1137.     while(!scr_csts());
  1138. }
  1139.  
  1140. getint()    /* error check an input line & return int */
  1141. {
  1142.     char inln[20],*b,flag;
  1143. stg:
  1144.     _gets(inln,20);
  1145.     if(strlen(inln))    {
  1146.         for(b=inln;*b!='\0';++b)    {
  1147.             if(!isdigit(*b) && *b != '-')    {
  1148.                 putchar(7);
  1149.                 goto stg;
  1150.             }
  1151.         }
  1152.         return(atoi(inln));
  1153.     }
  1154.     else
  1155.         putchar(7);
  1156.     goto stg;
  1157. }
  1158.  
  1159. /*    ED_IN_FILT
  1160.     This routine allows the user to edit the input filter
  1161. */
  1162. ed_in_filt()
  1163. {
  1164.     int n;
  1165.     scr_cla();
  1166.     scr_rowcol(0,26);
  1167.         printf("Edit Input Filter\n");
  1168.         printf("%s\n\n",sin_line);
  1169. st_filt:
  1170.     scr_rowcol(3,0);
  1171.     printf("             Mess #:    Message type:           Status:\n");
  1172.     printf("            ──────────┬────────────────────────┬───────────\n");
  1173.     printf("               1      │  Note ON               │   %s\n",(in_filt & 1) ? yes : no);
  1174.     printf("               2      │  Note OFF              │   %s\n",(in_filt & 2) ? yes : no);
  1175.     printf("               3      │  Program Change        │   %s\n",(in_filt & 4) ? yes : no);
  1176.     printf("               4      │  Channel Pressure      │   %s\n",(in_filt & 8) ? yes : no);
  1177.     printf("               5      │  Pitch Wheel           │   %s\n",(in_filt & 16) ? yes : no);
  1178.     printf("               6      │  Control Change        │   %s\n",(in_filt & 32) ? yes : no);
  1179.     printf("               7      │  Poly. Key Pressure    │   %s\n",(in_filt & 64) ? yes : no);
  1180.     printf("            ──────────┴────────────────────────┴───────────\n");
  1181.     printf("\n\n\n\n\n");
  1182. re_try:
  1183.     scr_rowcol(18,12);
  1184.     printf("Enter Message Number to toggle, 0 to end: ");
  1185.     n=getint();
  1186.     if(n<0 || n>7)
  1187.         goto re_try;
  1188.     if(!n)
  1189.         return;
  1190.     n=1 << (n-1);    /* make n into bit to complement */
  1191.     in_filt = in_filt & n ? in_filt-n : in_filt+n;
  1192.     goto st_filt;
  1193.  
  1194. }
  1195.  
  1196. get_options()    /* enter various user options */
  1197. {
  1198.  
  1199. em:     printf("Enter metrenome speed:");
  1200.         r_tempo=getint();
  1201.         if(r_tempo<40 || r_tempo>200)
  1202.                 goto em;
  1203.         tempo=2000000/((r_tempo*48)/60);
  1204.         printf("Audio Sync (Y/N):");
  1205.         audmet=(toupper(getchar())=='Y') ? 1:0;
  1206.         putchar('\n');
  1207.         printf("Drum Sync (Y/N):");
  1208.         dsync=(toupper(getchar())=='Y') ? 1:0;
  1209.         putchar('\n');
  1210.         printf("MIDI Sync (Y/N):");
  1211.         MIDIsync=(toupper(getchar())=='Y') ? 1:0;
  1212. }
  1213.  
  1214. /* dir(fname,ext)
  1215.     char *fname,*ext;
  1216.  
  1217.     This function shows a directory of the currently logged directory
  1218.     and disk and print it on the screen in "five-across" format.
  1219. */
  1220.  
  1221. dir(fname,ext)   /* function to show directory of currently logged disk  & dir */
  1222. char *fname,*ext;    /* pointers to filename & extension */
  1223. {
  1224.  
  1225.         struct fcb {
  1226.                 char drive_num;
  1227.                 char filename[8];
  1228.                 char extension[3];
  1229.                 char rest[25];  /* the rest of the fcb */
  1230.         } fcb;
  1231.  
  1232.         struct fcb fcb2;
  1233.     unsigned dta_add, dta_seg;
  1234.         char filename[21];
  1235.     char flag=4;
  1236.     char cnt=80;
  1237.  
  1238.         fcb.drive_num=0;
  1239.     strcpy(filename,"                    ");
  1240.         strncpy(fcb.filename,fname,8);
  1241.         strncpy(fcb.extension,ext,3);
  1242.         _setmem(fcb.rest,25,0);
  1243.  
  1244.     _rax=0x2f00;    /* get current DTA */
  1245.     _doint(0x21);
  1246.     dta_add=_rbx;
  1247.     dta_seg=_res;    /* this is the offset & segment of the current DTA */
  1248.  
  1249.         _rdx=fcb;
  1250.         _rds=_showds();
  1251.         _rax=0x1100;
  1252.  
  1253.     scr_rowcol(6,0);
  1254.     printf("%s\n",sin_line);
  1255.     scr_rowcol(7,0);
  1256.     scr_cls();
  1257.         for(;;)    {
  1258.                 _doint(0x21);
  1259.         if((_rax & 0xff))
  1260.             break;    /* last file has been listed */
  1261.                 _lmove(20,dta_add,dta_seg,fcb2,_showds());
  1262.                 strncpy(filename,fcb2.filename,8);
  1263.                 filename[8]='.';
  1264.         filename[9]='\0';
  1265.                 strcat(filename,fcb2.extension);
  1266.         filename[12]='\0';
  1267.                 puts(filename);
  1268.         puts("    ");
  1269.         if(!flag)
  1270.             flag=5;
  1271.         if(!--cnt)    {
  1272.             printf("                    Hit any key to continue.");
  1273.             getchar();
  1274.             scr_rowcol(7,0);
  1275.             scr_cls();
  1276.             cnt=80;
  1277.             flag=4;
  1278.         }
  1279.         --flag;
  1280.                 _rax=0x1200;
  1281.         }
  1282. }
  1283.